﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CommonWFLibrary;
using System.Workflow.Runtime;
using System.Threading;
using System.Workflow.ComponentModel;
using System.IO;
using System.Diagnostics;

namespace CommonWFLibraryTest
{
    /// <summary>
    /// Test the long running WF activity
    /// </summary>
    [TestClass]
    public class t_LongRunningActivityBase
    {
        public t_LongRunningActivityBase()
        {
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        class LRSimple : LongRunningActivityBase
        {
            public static int _result = 0;
            [LongRunningMethod]
            public static void Run()
            {
                _result = 10;
            }
        }

        [TestMethod]
        public void TestSimpleWF()
        {
            LRSimple._result = 0;
            RunWFByType(typeof(LRSimple));
            Assert.IsTrue(LRSimple._result == 10, "The static item for the activity method was not set -- was activity actually run!?");
        }

        class LRSimpleInherit : LRSimple
        {
        }

        [TestMethod]
        public void TestSimpleWFInherrited()
        {
            /// Make sure we can pick up trivial inherritance activities
            LRSimpleInherit._result = 0;
            RunWFByType(typeof(LRSimpleInherit));
            Assert.IsTrue(LRSimpleInherit._result == 10, "The static item for the activity wasn't right!");
        }

        /// <summary>
        /// Run a test, throw exceptions back to user.
        /// </summary>
        /// <param name="wfActivity"></param>
        /// <param name="dict"></param>
        private static void RunWFByType(Type wfActivity, Dictionary<string, object> dict)
        {
            using (WorkflowRuntime runtime = new WorkflowRuntime())
            using (AutoResetEvent reset = new AutoResetEvent(false))
            {
                Exception exp = null;
                runtime.WorkflowCompleted += delegate { reset.Set(); };
                runtime.WorkflowTerminated += (o, args) => { exp = args.Exception; reset.Set(); };

                LongRunningActivityBase.RegisterService(runtime);
                runtime.StartRuntime();

                WorkflowInstance instance;
                instance = runtime.CreateWorkflow(wfActivity, dict);
                instance.Start();
                reset.WaitOne();

                if (exp != null)
                {
                    throw exp;
                }
            }
        }

        /// <summary>
        /// Run a WF, with persistance. Once the WF goes into the idle state kill the runtime. Restart it, and then
        /// see if the WF is restored or used correctly.
        /// </summary>
        /// <param name="wfActivity"></param>
        /// <param name="dict"></param>
        /// <param name="timeout"></param>
        /// <param name="cache"></param>
        /// <returns></returns>
        private static bool RunWFByTypeWithPersistance(Type wfActivity, Dictionary<string, object> dict, int timeout, DirectoryInfo cache)
        {
            return RunWFByTypeWithPersistance(wfActivity, dict, timeout, cache, 1);
        }

        /// <summary>
        /// Run a WF, with persistance. Once the WF goes into the idle state kill the runtime. We do this "n" times, and
        /// then see if the WF is restored and used correctly.
        /// </summary>
        /// <param name="wfActivity"></param>
        /// <param name="dict"></param>
        /// <param name="timeout"></param>
        /// <param name="cache"></param>
        /// <param name="numberCrashToIdles"></param>
        /// <returns></returns>
        private static bool RunWFByTypeWithPersistance(Type wfActivity, Dictionary<string, object> dict, int timeout, DirectoryInfo cache, int numberCrashToIdles)
        {
            ///
            /// Crash the runtime n times.
            /// 

            bool start_wf = true;
            bool has_entered_idle = false;
            while (numberCrashToIdles >= 0)
            {
                Trace.WriteLine("Starting WF runtime iteration");
                numberCrashToIdles = numberCrashToIdles - 1;
                bool waitForComplete = numberCrashToIdles < 0;

                ///
                /// Run until the WF enters the idle state. If it crashes, then, of course, we are outta here.
                /// 

                using (AutoResetEvent reset = new AutoResetEvent(false))
                using (WorkflowRuntime runtime = new WorkflowRuntime())
                {
                    try
                    {
                        Exception e = null;
                        bool completed = false;
                        if (!waitForComplete)
                        {
                            runtime.WorkflowIdled += (o, args) => { reset.Set(); has_entered_idle = true; };
                        }
                        runtime.WorkflowCompleted += (o, args) => { completed = true; reset.Set(); };
                        runtime.WorkflowTerminated += (o, args) => { e = args.Exception; reset.Set(); };

                        runtime.AddService(new FilePersistenceService(true, cache));
                        LongRunningActivityBinaryPersister lrp = new LongRunningActivityBinaryPersister(new FileInfo(cache.FullName + "\\longrunning"));
                        LongRunningActivityBase.RegisterService(runtime, obj => lrp.Save(obj), () => lrp.Restore());
                        runtime.StartRuntime();

                        ///
                        /// If this is the first time through, then we should start the WF. Otherwise, it
                        /// should have been picked up by the persitancy service from the last run.
                        /// 

                        if (start_wf)
                        {
                            WorkflowInstance instance;
                            instance = runtime.CreateWorkflow(wfActivity, dict);
                            instance.Start();
                            start_wf = false;
                        }

                        ///
                        /// Great. Now wait for it to finish. We expect the WF to enter
                        /// an idled state within 1 second. On the last one, waiting for something
                        /// real to happen, we expect that to happen in the timeout parameter passed
                        /// to us.
                        /// 
                        /// We shut down the runtime here so that we can step through the other statements in the
                        /// debugger!
                        /// 

                        int waittime = waitForComplete ? timeout : 1000;
                        bool result = reset.WaitOne(waittime);
                        runtime.StopRuntime();
                        runtime.Dispose();

                        ///
                        /// First, if the WF ended due to an exception, we are outta here no matter what
                        /// 

                        if (e != null)
                        {
                            throw e;
                        }

                        ///
                        /// Next, if we are waiting for a complete, then we just return the result
                        /// 

                        if (waitForComplete)
                        {
                            return result;
                        }

                        ///
                        /// Ok -- we were waiting for things to go into the idle state. Bomb if they didn't,
                        /// otherwise we go around again!
                        /// 

                        if (completed)
                        {
                            throw new Exception("The WF unexpectedly completed before going idle!");
                        }
                        if (!result && !has_entered_idle)
                        {
                            throw new Exception("The workflow was never idled");
                        }
                    }
                    finally
                    {
                        if (runtime.IsStarted)
                        {
                            runtime.StopRuntime();
                        }
                    }
                }
            }
            return false;
        }

        private static void RunWFByType(Type wfActivity)
        {
            RunWFByType(wfActivity, null);
        }

        /// <summary>
        /// WF that will wait for some period of time before actually causing the thing
        /// to fail.
        /// </summary>
        class LWFTime : LongRunningActivityBase
        {
            public int Ticks { get; set; }

            public LWFTime()
            {
            }
            [Serializable]
            public class cArgs
            {
                public int _args;
                public cArgs(int a)
                {
                    _args = a;
                }
            }
            [LongRunningMethod]
            public static void Run(cArgs a)
            {
                Thread.Sleep(a._args);
            }
            [LongRunningGatherArguments]
            public cArgs Args()
            {
                return new cArgs(Ticks);
            }
        }

        [TestMethod]
        public void TestPrematureShutdown()
        {
            ///
            /// If the workflow engine shuts down, make sure we don't cause a crash by trying to reference
            /// something that is in there...
            /// 

            using (WorkflowRuntime runtime = new WorkflowRuntime())
            using (AutoResetEvent reset = new AutoResetEvent(false))
            {
                runtime.WorkflowIdled += delegate { reset.Set(); };

                LongRunningActivityBase.RegisterService(runtime);
                runtime.StartRuntime();

                WorkflowInstance instance;
                instance = runtime.CreateWorkflow(typeof(LWFTime), new Dictionary<string,object> {{"Ticks", 3000}});
                instance.Start();
                reset.WaitOne();

                runtime.StopRuntime();
            }

            ///
            /// Now wait for the ticks guy to time out. While this guy may finish, it will cause a crash
            /// in the vshost dude.
            /// 

            Thread.Sleep(4000);
        }

        [TestMethod]
        public void TestLostService()
        {
            /// Test the fact that the service was not added in

            using (WorkflowRuntime runtime = new WorkflowRuntime())
            using (AutoResetEvent reset = new AutoResetEvent(false))
            {
                Exception exp = null;
                runtime.WorkflowCompleted += delegate { reset.Set(); };
                runtime.WorkflowTerminated += (o, args) => { exp = args.Exception; reset.Set(); };
                runtime.StartRuntime();

                WorkflowInstance instance;
                instance = runtime.CreateWorkflow(typeof(LRSimple));
                instance.Start();
                reset.WaitOne();

                Assert.IsTrue(exp != null, "No exception was thrown by the wf!");
                Assert.IsTrue(exp.Message.Contains("Service"), "Exception thrown is wrong exception for missing WF serice!");
            }
        }

        [TestMethod]
        public void TestThrow()
        {
            /// Make sure we throw an exception because we don't have a "run" method.
            try
            {
                RunWFByType(typeof(LongRunningActivityBase));
            }
            catch (Exception e)
            {
                Assert.IsTrue(e.Message.Contains("LongRunningMethod"), "Wrong exception came back for missing Run method!");
                return;
            }
            Assert.Fail("An exception should have been thrown!");
        }

        [TestMethod]
        public void Test05secWF()
        {
            TimeSpan sp = RunTimeTest(500);
            Assert.IsTrue(sp.TotalMilliseconds > 500, "Run took less than half a second - pause didn't work");
        }

        /// <summary>
        /// Run a timer test...
        /// </summary>
        /// <returns></returns>
        private static TimeSpan RunTimeTest(int ticks)
        {
            /// Wait for 0.5 second and make sure that it actually takes that long to complete.
            DateTime now = DateTime.Now;
            RunWFByType(typeof(LWFTime), new Dictionary<string,object> {{"Ticks", ticks}});
            DateTime then = DateTime.Now;
            TimeSpan sp = then - now;
            return sp;
        }

        [TestMethod]
        public void TestFastWF()
        {
            TimeSpan sp = RunTimeTest(0);
            Assert.IsTrue(sp.TotalMilliseconds < 300, "Run took more than half a second - pause didn't work");
        }

        /// <summary>
        /// Activity that will set some information on the way back down.
        /// </summary>
        public class LWASetResult : LongRunningActivityBase
        {
            public class cArgs
            {
                public int _arg;
            }

            public int TheArg { get; set; }

            [LongRunningMethod]
            public static cArgs Run(cArgs arg)
            {
                cArgs newarg = new cArgs();
                newarg._arg = arg._arg * 2;
                return newarg;
            }

            [LongRunningGatherArguments]
            public cArgs GatherArgs()
            {
                cArgs result = new cArgs();
                result._arg = TheArg;
                return result;
            }

            public static int _result;

            [LongRunningDistributeArguments]
            public void DoneWithResult(cArgs arg)
            {
                _result = arg._arg;
            }
        }

        [TestMethod]
        public void TestArgDistribution()
        {
            LWASetResult._result = 0;
            RunWFByType(typeof(LWASetResult), new Dictionary<string, object> { { "TheArg", 10 } });
            Assert.IsTrue(LWASetResult._result == 20, "The callback didn't set the result to the right value!");
        }

        [TestMethod]
        public void TestPersistance()
        {
            try
            {
                Assert.IsTrue(RunWFByTypeWithPersistance(typeof(LWFTime), new Dictionary<string, object> { { "Ticks", 3000 } }, 5000, new DirectoryInfo(".\\testPers")), "The task did not complete");
                Assert.Fail("The persistance should have thrown a crash - because it didn't restart, but that didn't happen");
            }
            catch (LongRunningException e)
            {
                Assert.IsTrue(e.Message.Contains("Activity was waiting for response"), "Incorrect crash came back from aborted WF.");
            }
        }

        [TestMethod]
        public void TestAbortedWF()
        {
            DirectoryInfo cache = new DirectoryInfo (".\\TestAbortedWF");

            ///
            /// Get the runtime going, go into idle state, and then abort the workflow. There should
            /// be no files sitting in the cache directory at that point.
            /// 

            using (WorkflowRuntime runtime = new WorkflowRuntime())
            using (AutoResetEvent reset = new AutoResetEvent(false))
            {
                Exception exp = null;
                runtime.WorkflowCompleted += delegate { reset.Set(); };
                runtime.WorkflowTerminated += (o, args) => { exp = args.Exception; reset.Set(); };
                runtime.WorkflowIdled += (o, args) => reset.Set();

                runtime.AddService(new FilePersistenceService(true, cache));
                LongRunningActivityBinaryPersister lrp = new LongRunningActivityBinaryPersister(new FileInfo(cache.FullName + "\\longrunning"));
                LongRunningActivityBase.RegisterService(runtime, obj => lrp.Save(obj), () => lrp.Restore());
                runtime.StartRuntime();

                WorkflowInstance instance;
                instance = runtime.CreateWorkflow(typeof(LWFTime), new Dictionary<string, object> { { "Ticks", 5000 } });
                instance.Start();
                reset.WaitOne();

                if (exp != null)
                {
                    throw exp;
                }

                ///
                /// Ok -- now check out the cache. Make sure there are no files there!
                /// 

                instance.Terminate("Forcing terminate for testing");

                Assert.IsTrue(cache.GetFiles().Length == 0, "There were files in the cache after aborted WF!");
            }
        }

        [TestMethod]
        public void TestAutoRestart()
        {
            Assert.IsTrue(RunWFByTypeWithPersistance(typeof(LWFTime), new Dictionary<string, object> { { "Ticks", 3000 }, { "TimesToRetry", 1 } }, 5000, new DirectoryInfo(".\\testAutoRestart")), "The task did not complete");
        }

        /// <summary>
        /// A simple activity that will throw...
        /// </summary>
        class LRCrashNTimesActivity : LongRunningActivityBase
        {
            public static int _numberOfTimes = 0;

            public int TimesToCrash { get; set; }

            [Serializable]
            public class cArgs
            {
                public int _times;
            }

            [LongRunningMethod]
            public static void Run(cArgs args)
            {
                _numberOfTimes = _numberOfTimes + 1;

                if (_numberOfTimes < args._times)
                {
                    Thread.Sleep(2000);
                }
                else
                {
                    throw new Exception("Testing the throw 12345669");
                }
            }

            [LongRunningGatherArguments]
            public cArgs Gather()
            {
                cArgs c = new cArgs();
                c._times = TimesToCrash;
                return c;
            }
        }

        [TestMethod]
        public void TestNumberCalls()
        {
            /// Make sure that the WF above is called the number of times we expect it to be called.
            /// This is more of a test of the test harness than it is of the long running activity code. :-)

            LRCrashNTimesActivity._numberOfTimes = 0;
            RunWFByType(typeof(LRCrashNTimesActivity),
                new Dictionary<string, object> { { "TimesToCrash", 10 } });
            Assert.IsTrue(LRCrashNTimesActivity._numberOfTimes == 1, "Was expecting to have run only once!");

            LRCrashNTimesActivity._numberOfTimes = 0;
            bool result = RunWFByTypeWithPersistance(typeof(LRCrashNTimesActivity),
                new Dictionary<string, object> { { "TimesToCrash", 10 } },
                5000,
                new DirectoryInfo(".\\TestNumberCallsCache"),
                0);
            Assert.IsTrue(result, "Expected complex run with 0 retries to come back just fine!");
            Assert.IsTrue(LRCrashNTimesActivity._numberOfTimes == 1, "Expected the activity to be called only one time!");

            LRCrashNTimesActivity._numberOfTimes = 0;
            bool result2 = RunWFByTypeWithPersistance(typeof(LRCrashNTimesActivity),
                new Dictionary<string, object> { { "TimesToCrash", 10 }, {"TimesToRetry", 10} },
                5000,
                new DirectoryInfo(".\\TestNumberCallsCache"),
                1);
            Assert.IsTrue(result2, "Expected complex run with 1 retries to come back just fine!");
            Assert.IsTrue(LRCrashNTimesActivity._numberOfTimes == 2, "Expected the activity to be called exactly 2 times.");
        }

        [TestMethod]
        public void TestForPersFileToBeGone()
        {
            DirectoryInfo di = new DirectoryInfo(".\\TestNumberCallsCache");
            LRCrashNTimesActivity._numberOfTimes = 0;
            bool result = RunWFByTypeWithPersistance(typeof(LRCrashNTimesActivity),
                new Dictionary<string, object> { { "TimesToCrash", 10 } },
                5000,
                di,
                0);
            Assert.IsTrue(result, "Expected complex run with 0 retries to come back just fine!");
            Assert.IsTrue(LRCrashNTimesActivity._numberOfTimes == 1, "Expected the activity to be called only one time!");

            FileInfo fcache = new FileInfo(di.FullName + "\\longrunning");
            Assert.IsFalse(fcache.Exists, "The cache file should not be around after a single successful run!");
        }

        [TestMethod]
        public void TestAutoRerunExactNumberOfTimes()
        {
            ///
            /// First, make sure that if we retry several times it gets a chance to complete.
            /// 

            LRCrashNTimesActivity._numberOfTimes = 0;
            bool result2 = RunWFByTypeWithPersistance(typeof(LRCrashNTimesActivity),
                new Dictionary<string, object> { { "TimesToCrash", 10 }, { "TimesToRetry", 3 } }, 5000,
                new DirectoryInfo(".\\TestAutoRerunExactNumberOfTimes"), 3);
            Assert.IsTrue(result2, "Was expecting things to complete normally");
            Assert.IsTrue(LRCrashNTimesActivity._numberOfTimes == 4, "Was expecting to have called the activity exactly 4 times!");
        }

        [TestMethod]
        public void TestExcessiveAutoRestart()
        {
            ///
            /// This looks to make sure we are safe against the thing that the task we are doing
            /// causes the whole host to crash. So we specify the max number of times to re-try a
            /// particular WF item.
            /// 

            try
            {
                LRCrashNTimesActivity._numberOfTimes = 0;
                bool result = RunWFByTypeWithPersistance(typeof(LRCrashNTimesActivity),
                    new Dictionary<string, object> { { "TimesToCrash", 10 }, { "TimesToRetry", 4 } }, 5000,
                    new DirectoryInfo(".\\TestExcessiveAutoRestart"),
                    10);
                Assert.Fail("We should have thrown an exception and terminated after the 2nd iteration and note made it to the third!");
            }
            catch (Exception e)
            {
                Assert.IsTrue(e.Message.Contains("waiting for response"), "Exception that came back was incorrect");
                Assert.IsTrue(LRCrashNTimesActivity._numberOfTimes == 5, "Was expecting to have retried only 5 times before a crash!");
            }
        }

        /// <summary>
        /// A simple activity that will throw...
        /// </summary>
        class LRCrashActivity : LongRunningActivityBase
        {
            [LongRunningMethod]
            public static void Run()
            {
                throw new Exception("Testing the throw 123456789");
            }
        }

        [TestMethod]
        public void TestWFThrows()
        {
            try
            {
                RunWFByType(typeof(LRCrashActivity));
                Assert.Fail("WF completed without an error - it should have thrown!");
            }
            catch (Exception e)
            {
                Assert.IsNotNull(e.InnerException, "Inner expcetion is not null!");
                Assert.IsTrue(e.InnerException.Message.Contains("123456789"), "Wrong exception came back from crashed WF");
            }
        }

        class LRAsyncActivity : LongRunningActivityBase
        {
            /// <summary>
            /// How many ticks to wait for!
            /// </summary>
            public int Ticks { get; set; }

            public class cArgs
            {
                public int _ticks;
            }

            [LongRunningGatherArguments]
            public cArgs Gather()
            {
                var result = new cArgs();
                result._ticks = Ticks;
                return result;
            }

            [LongRunningMethodStarter]
            public static void StartTimer(LongRunningContext c, cArgs args)
            {
                Timer t = new Timer(new TimerCallback(timerdone), c, args._ticks, Timeout.Infinite);
            }

            public static void timerdone(object state)
            {
                LongRunningContext c = state as LongRunningContext;
                c.Complete();
            }
        }

        [TestMethod]
        public void TestAsyncCallbackPattern()
        {
            /// Use a guy that doesn't run synchronosly - rather runs async.
            RunWFByType(typeof(LRAsyncActivity), new Dictionary<string, object> { { "Ticks", 1000 } });
        }

        class LRAsyncNoArgActivity : LongRunningActivityBase
        {
            [LongRunningMethodStarter]
            public static void StartTimer(LongRunningContext c)
            {
                Timer t = new Timer(new TimerCallback(timerdone), c, 1000, Timeout.Infinite);
            }

            public static void timerdone(object state)
            {
                LongRunningContext c = state as LongRunningContext;
                c.Complete();
            }
        }

        [TestMethod]
        public void TestAsyncCallbackPatternNoArgs()
        {
            /// WF with a run method that takes no parameters
            RunWFByType(typeof(LRAsyncNoArgActivity));
        }

        class LRAsyncActivityWithArgs : LongRunningActivityBase
        {
            /// <summary>
            /// How many ticks to wait for!
            /// </summary>
            public int Ticks { get; set; }

            public class cArgs
            {
                public int _ticks;
            }

            [LongRunningGatherArguments]
            public cArgs Gather()
            {
                var result = new cArgs();
                result._ticks = Ticks;
                return result;
            }

            [LongRunningMethodStarter]
            public static void StartTimer(LongRunningContext c, cArgs args)
            {
                Timer t = new Timer(new TimerCallback(timerdone), c, args._ticks, Timeout.Infinite);
            }

            public static void timerdone(object state)
            {
                LongRunningContext c = state as LongRunningContext;
                Result r = new Result();
                r._result = 15;
                c.Complete(r);
            }

            public class Result
            {
                public int _result;
            }

            public static int _result = 0;

            [LongRunningDistributeArguments]
            public void Save(Result r)
            {
                _result = r._result;
            }

        }

        [TestMethod]
        public void TestAsyncWFWithResult()
        {
            LRAsyncActivityWithArgs._result = 0;
            RunWFByType(typeof(LRAsyncActivityWithArgs), new Dictionary<string, object> { { "Ticks", 500 } });
            Assert.IsTrue(LRAsyncActivityWithArgs._result == 15, "The saved result was not correct");
        }

        class LRAsyncActivityWithContext : LongRunningActivityBase
        {
            /// <summary>
            /// How many ticks to wait for!
            /// </summary>
            public int Ticks { get; set; }

            [Serializable]
            public class cArgs
            {
                public int _ticks;
            }

            [Serializable]
            public class MyContext
            {
                public int _mycounter = 0;
            }

            [LongRunningGatherArguments]
            public cArgs Gather()
            {
                var result = new cArgs();
                result._ticks = Ticks;
                return result;
            }

            [LongRunningMethodStarter]
            public static MyContext StartTimer(LongRunningContext c, cArgs args, MyContext me)
            {
                MyContext newme = new MyContext();
                newme._mycounter = 1;
                if (me != null)
                {
                    newme._mycounter = newme._mycounter + me._mycounter;
                }
                Trace.WriteLine("Starting Timer -- counter is " + newme._mycounter.ToString());

                Timer t = new Timer(new TimerCallback(timerdone), new object[] { c, newme }, args._ticks, Timeout.Infinite);

                return newme;
            }

            public static void timerdone(object state)
            {
                object[] arr = state as object[];
                LongRunningContext c = arr[0] as LongRunningContext;
                MyContext me = arr[1] as MyContext;

                Result r = new Result();
                r._result = 15;
                r._counter = me._mycounter;
                c.Complete(r);
            }

            [Serializable]
            public class Result
            {
                public int _result;
                public int _counter;
            }

            public static int _result = 0;
            public static int _counter = 0;

            [LongRunningDistributeArguments]
            public void Save(Result r)
            {
                _result = r._result;
                _counter = r._counter;
            }
        }

        [TestMethod]
        public void TestAsyncWithContext()
        {
            LRAsyncActivityWithContext._counter = 0;
            LRAsyncActivityWithContext._result = 0;
            RunWFByType(typeof(LRAsyncActivityWithContext));

            Assert.IsTrue(LRAsyncActivityWithContext._result == 15, "The result is not correct");
            Assert.IsTrue(LRAsyncActivityWithContext._counter == 1, "The number of times it was called is not four!");
        }

        [TestMethod]
        public void TestAsyncWithContextAndCrash()
        {
            /// Make sure the updated context is correctly written out to the cache.
            /// It doesn't appear to be in one of the long running program tests.
            LRAsyncActivityWithContext._counter = 0;
            LRAsyncActivityWithContext._result = 0;
            RunWFByTypeWithPersistance(typeof(LRAsyncActivityWithContext), new Dictionary<string, object> { { "Ticks", 8000 }, {"TimesToRetry", 5} }, 10000,
                new DirectoryInfo(".\\TestAsyncWithContextAndCrash"),
                4);

            Assert.IsTrue(LRAsyncActivityWithContext._result == 15, "The result is not correct");
            Assert.IsTrue(LRAsyncActivityWithContext._counter == 5, "The number of times it was called is not one!");
        }
    }
}
